/**
*********************************************************************************************************
*               Copyright(c) 2018, Realtek Semiconductor Corporation. All rights reserved.
**********************************************************************************************************
* @file     hci_app.c
* @brief
* @details
* @author
* @date
* @version
*********************************************************************************************************
*/

/* Includes ------------------------------------------------------------------*/
///#define LOG_TAG    "HCIAPP"
#include "asr_rtl8763bo_port.h"

#if USE_LV_BLUETOOTH != 0

#include "hci_app.h"
#include "rtl8763bf_task.h"
#include "localplay.h"
#include "headset.h"



#include "bt_api.h"


#define COD_TYPE_HEADSET    0x400
#define COD_TYPE_PHONE      0x200

extern struct bt_event_inquiry * ScanTable;
extern uint32_t btInquiedDevice;
extern bool m_bBtPowerOn;
extern volatile uint8_t m_btInquiryState;
extern bool m_bHeadsetConnected;

extern bt_uart_cfg rtlbt_uart_port;

extern rbuf_t * g_pcm_tx_rbuf;
extern rbuf_t * g_pcm_rx_rbuf;

extern uint8_t sbcframe_request_flag;
///extern void BT_SendMessage2MMI(msg_type_t msg_id, void *msg_ptr, unsigned int msg_len);

extern void uart_test_main(uint32 port_id);
extern int appbt_a2dp_media_init(void);

extern void bbpro_send_pcm_data(short * pData, unsigned short Length);
extern void bbpro_receive_pcm_data(short * pData, unsigned short Length);
extern void AudioHAL_AifClose(void);


int bbpro_send_sbc_frame(void * data, uint8_t n_frames, uint16_t n_bytes);
int bbpro_request_sbc_play(void);
int bbpro_request_sbc_pause(void);
int bbpro_request_sbc_stop(void);
int bbpro_request_sbc_prev(void);
int bbpro_request_sbc_next(void);


#define MEDIA_PROCESS_FLAG_CONTINUE     (1 << 1)


extern uint8_t sbcframe_request_flag;




static bt_event_handle_t bt_user_event_handler = NULL;

typedef int (*sbc_send_cb_t)(void * data, uint8_t n_frames, uint16_t n_bytes);
typedef int (*sbc_play_cb_t)(void);
typedef int (*sbc_pause_cb_t)(void);
typedef void (*send_event_cb_t)(struct bt_task_event * event);
extern void appbt_a2dp_register_sbc_cb(sbc_send_cb_t send, sbc_play_cb_t play, sbc_pause_cb_t pause);
extern void appbt_a2dp_register_event_cb(send_event_cb_t send);

typedef void (*POCTxPCMHandler_t)(short * pData, unsigned short Length);
typedef void (*POCRxPCMHandler_t)(short * pData, unsigned short Length);
extern int POCVoice_BindPCMHandler(POCTxPCMHandler_t, POCRxPCMHandler_t);
extern int POCVoice_UnBindPCMHandler(POCTxPCMHandler_t, POCRxPCMHandler_t);
extern void AcmSetPCMRate(BOOL wb);

extern void bbpro_start_pcm_tx_timer(void);
extern void bbpro_stop_pcm_tx_timer(void);

#ifndef AUDIO_PLAY_NORMAL
extern void test_pcm_tx_rx_start(void);
extern void test_pcm_tx_rx_stop(void);
#endif


T_BT_STATUS RtkWristbandSys;

int8_t bbpro_play_state = -1;

uint8_t bbpro_bd_addr[6];
bool bbpro_bd_addr_got_flag = false;
HCI_EVENT_CB bbpro_hci_event_cb = NULL;
static bool pairing_key_missing_flag = false;

bool hci_module_has_installed = false;

extern uint8_t bbpro_peer_bd_addr[];

static const char * parseProfile(uint16_t profile)
{
    const char * stateStr = NULL;

    switch(profile) {
        case A2DP_PROFILE_MSAK:
            stateStr = "A2DP";
            break;
        case AVRCP_PROFILE_MSAK:
            stateStr = "AVRCP";
            break;
        case HFHS_PROFILE_MSAK:
            stateStr = "HFHS";
            break;
        case MULTI_SPEAKER_PROFILE_MSAK:
            stateStr = "MULTI_SPEAKER";
            break;
        case SPP_PROFILE_MSAK:
            stateStr = "SPP";
            break;
        case IAP_PROFILE_MSAK:
            stateStr = "IAP";
            break;
        case PBAP_PROFILE_MSAK:
            stateStr = "PBAP";
            break;

        default:
            stateStr = "RESERVED";
            break;
    }

    return stateStr;
}

static const char * parseCallStatus(uint8_t status)
{
    const char * stateStr = NULL;

    switch(status) {
        case CALL_STATUS_CALL_IDLE:
            stateStr = "CALL_IDLE";
            break;
        case CALL_STATUS_VOICE_ACTIVATION_ONGOING:
            stateStr = "VOICE_ACTIVATION_ONGOING";
            break;
        case CALL_STATUS_INCOMING_CALL_ONGOING:
            stateStr = "INCOMING_CALL_ONGOING";
            break;
        case CALL_STATUS_OUTCOMING_CALL_ONGOING:
            stateStr = "OUTCOMING_CALL_ONGOING";
            break;
        case CALL_STATUS_CALL_ACTIVE:
            stateStr = "CALL_ACTIVE";
            break;
        case CALL_STATUS_CALL_ACTIVE_WITH_CALL_WAITING:
            stateStr = "CALL_ACTIVE_WITH_CALL_WAITING";
            break;
        case CALL_STATUS_CALL_ACTIVE_WITH_CALL_HODE:
            stateStr = "CALL_ACTIVE_WITH_CALL_HODE";
            break;

        default:
            stateStr = "RESERVED";
            break;
    }

    return stateStr;
}

int bbpro_sw_init(void)
{
    int ret = 0;

    MODLOGD("%s++", __func__);

    /* Initialize HCI protocol layer data struct */
    DataTrans_hci_data_struct_init();
    /* Initialize HCI physical layer */
    DataTrans_InitQueue();

    bbpro_hci_task_init();

    bbpro_hci_event_cb = talkband_bbpro_hci_event_cb;
    pairing_key_missing_flag = false;
    hci_module_has_installed = true;

    ///sbcframe_queue_create();

    appbt_a2dp_media_init();

    MODLOGD("%s--", __func__);

    return ret;
}

int bbpro_sw_deinit(void)
{
    int ret = 0;

    MODLOGD("%s++", __func__);

    bbpro_hci_task_deinit();
    bbpro_hci_event_cb = NULL;

    ///sbcframe_queue_delete();

    MODLOGD("%s--", __func__);

    return ret;
}

int bbpro_hw_init(void)
{
    int ret = 0;

    MODLOGD("%s++", __func__);

    DataTrans_Board_UART_Init(0, 0);
    DataTrans_Driver_UART_Init();

    MODLOGD("%s--", __func__);

    return ret;
}

int bbpro_hw_deinit(void)
{
    int ret = 0;

    MODLOGD("%s++", __func__);

    MODLOGD("%s--", __func__);

    return ret;
}

int bbpro_open(bt_event_handle_t handle)
{
    int ret = 0;

    MODLOGD("%s++", __func__);

    /*
     * 0: nb, 8k
     * 1: wb, 16k
     */
    AcmSetPCMRate(1);

    bt_user_event_handler = handle;
    appbt_a2dp_register_sbc_cb(bbpro_send_sbc_frame, bbpro_request_sbc_play, bbpro_request_sbc_pause);
    appbt_a2dp_register_event_cb(handle);

    bbpro_hw_init();
    bbpro_sw_init();

#if (AUDIO_PATH_SELECT == AUDIO_PATH_TX_RX_NORMAL)
    {
        T_HCI_MSG msg;

        msg.type = HCI_MSG_TYPE_8763BF;
        msg.subtype = BBPRO_HCI_RESET_TO_DEFAULT;
        bbpro_hci_msg_queue_send(&msg);

        msg.type = HCI_MSG_TYPE_8763BF;
        msg.subtype = BBPRO_HCI_SEND_POWER_ON_PRESSED;
        bbpro_hci_msg_queue_send(&msg);

        msg.type = HCI_MSG_TYPE_8763BF;
        msg.subtype = BBPRO_HCI_SET_PLAY_MODE;
        msg.u.param = BOM_PLAY_MODE_A2DP_SOURCE;
        bbpro_hci_msg_queue_send(&msg);

        msg.type = HCI_MSG_TYPE_8763BF;
        msg.subtype = BBPRO_HCI_CMD_I2S_STATUS;
        msg.u.param = 1;
        bbpro_hci_msg_queue_send(&msg);
    }
#else // loopback test
    {
#if ((AUDIO_TX_SELECT == AUDIO_TX_AUDIOHAL) || (AUDIO_RX_SELECT == AUDIO_RX_AUDIOHAL))
        {
            AUDIOHAL_AIF_DEVICE_CFG_T AudioHAL_config;
            AUDIOHAL_ITF_T AudioHAL_itf = AUDIOHAL_ITF_HEADPHONE; ///AUDIOHAL_ITF_LOUDSPEAKER;

            memset(&AudioHAL_config, 0, sizeof(AUDIOHAL_AIF_DEVICE_CFG_T));
            AudioHAL_AifOpen(AudioHAL_itf, &AudioHAL_config);

#if ((AUDIO_TX_SELECT == AUDIO_TX_AUDIOHAL) && (AUDIO_RX_SELECT == AUDIO_RX_AUDIOHAL))
            POCVoice_BindPCMHandler(bbpro_send_pcm_data, bbpro_receive_pcm_data);
#elif(AUDIO_TX_SELECT == AUDIO_TX_AUDIOHAL)
            POCVoice_BindPCMHandler(bbpro_send_pcm_data, NULL);
#elif(AUDIO_RX_SELECT == AUDIO_RX_AUDIOHAL)
            POCVoice_BindPCMHandler(NULL, bbpro_receive_pcm_data);
#endif
        }
#endif
        test_pcm_tx_rx_start();

        bbpro_start_pcm_tx_timer();
    }
#endif

    MODLOGD("%s--", __func__);

    return ret;
}

int bbpro_close(void)
{
    int ret = 0;

    MODLOGD("%s++", __func__);

#if (AUDIO_PATH_SELECT == AUDIO_PATH_TX_RX_NORMAL)
    {
        T_HCI_MSG msg;

#if 0
        msg.type = HCI_MSG_TYPE_8763BF;
        msg.subtype = BBPRO_HCI_RESET_TO_DEFAULT;
        bbpro_hci_msg_queue_send(&msg);
#endif
        msg.type = HCI_MSG_TYPE_8763BF;
        msg.subtype = BBPRO_HCI_SEND_POWER_OFF_PRESSED;
        bbpro_hci_msg_queue_send(&msg);
    }
#else
    {
#if ((AUDIO_TX_SELECT == AUDIO_TX_AUDIOHAL) || (AUDIO_RX_SELECT == AUDIO_RX_AUDIOHAL))
        {
            AudioHAL_AifClose();

#if ((AUDIO_TX_SELECT == AUDIO_TX_AUDIOHAL) && (AUDIO_RX_SELECT == AUDIO_RX_AUDIOHAL))
            POCVoice_UnBindPCMHandler(bbpro_send_pcm_data, bbpro_receive_pcm_data);
#elif (AUDIO_TX_SELECT == AUDIO_TX_AUDIOHAL)
            POCVoice_UnBindPCMHandler(bbpro_send_pcm_data, NULL);
#elif (AUDIO_RX_SELECT == AUDIO_RX_AUDIOHAL)
            POCVoice_UnBindPCMHandler(NULL, bbpro_receive_pcm_data);
#endif
        }
#endif

        test_pcm_tx_rx_stop();

        bbpro_stop_pcm_tx_timer();
    }
#endif

    MODLOGD("%s--", __func__);

    return ret;
}

int bbpro_inquiry(void)
{
    T_HCI_MSG msg;
    int ret = 0;

    MODLOGD("bbpro_inquiry()\n");

    msg.type = HCI_MSG_TYPE_8763BF;
    msg.subtype = BBPRO_HCI_INQUIRY_START;
    msg.u.inquiry_param.filter = 0x24;
    msg.u.inquiry_param.rssi = 0xC4;
    msg.u.inquiry_param.inquiry_time = 30;///0x05;
    bbpro_hci_msg_queue_send(&msg);

    return ret;
}
int bbpro_inquiry_stop(void)
{
    T_HCI_MSG msg;
    int ret = 0;

    MODLOGD("bbpro_inquiry_stop()\n");

    msg.type = HCI_MSG_TYPE_8763BF;
    msg.subtype = BBPRO_HCI_INQUIRY_STOP;
    bbpro_hci_msg_queue_send(&msg);

    return ret;
}

int  bbpro_create_connection(uint8_t * bt_addr)
{
    T_HCI_MSG msg;
    int ret = 0;

    MODLOGD("create connection: addr %02x%02x%02x%02x%02x%02x.\n",
            bt_addr[0], bt_addr[1], bt_addr[2],
            bt_addr[3], bt_addr[4], bt_addr[5]);

    memcpy(bbpro_peer_bd_addr, bt_addr, 6);

    msg.type = HCI_MSG_TYPE_8763BF;
    msg.subtype = BBPRO_HCI_CREATE_CONNECTION;
    msg.len = 6;
    msg.u.buf = bbpro_peer_bd_addr;
    bbpro_hci_msg_queue_send(&msg);

    return ret;
}

int bbpro_request_sbc_play(void)
{
    T_HCI_MSG msg;
    int ret = 0;

    ///MODLOGD("bbpro_request_sbc_play()\n");

    msg.type = HCI_MSG_TYPE_8763BF;
    msg.subtype = BBPRO_HCI_REQ_SBC_OPERATION_PLAY;
    bbpro_hci_msg_queue_send(&msg);

    bbpro_play_state = SBC_OPERATION_PLAY;

    return ret;
}

int bbpro_request_sbc_pause(void)
{
    T_HCI_MSG msg;
    int ret = 0;

    ///MODLOGD("bbpro_request_sbc_pause()\n");

    msg.type = HCI_MSG_TYPE_8763BF;
    msg.subtype = BBPRO_HCI_REQ_SBC_OPERATION_PAUSE;
    bbpro_hci_msg_queue_send(&msg);

    bbpro_play_state = SBC_OPERATION_PAUSE;

    return ret;
}

int bbpro_request_sbc_stop(void)
{
    T_HCI_MSG msg;
    int ret = 0;

    ///MODLOGD("bbpro_request_sbc_stop()\n");

    msg.type = HCI_MSG_TYPE_8763BF;
    msg.subtype = BBPRO_HCI_REQ_SBC_OPERATION_STOP;
    bbpro_hci_msg_queue_send(&msg);

    bbpro_play_state = SBC_OPERATION_STOP;

    return ret;
}

int bbpro_request_sbc_prev(void)
{
    T_HCI_MSG msg;
    int ret = 0;

    ///MODLOGD("bbpro_request_sbc_prev()\n");

    msg.type = HCI_MSG_TYPE_8763BF;
    msg.subtype = BBPRO_HCI_REQ_SBC_OPERATION_PREV;
    bbpro_hci_msg_queue_send(&msg);

    bbpro_play_state = SBC_OPERATION_PREV;

    return ret;
}

int bbpro_request_sbc_next(void)
{
    T_HCI_MSG msg;
    int ret = 0;

    ///MODLOGD("bbpro_request_sbc_next()\n");

    msg.type = HCI_MSG_TYPE_8763BF;
    msg.subtype = BBPRO_HCI_REQ_SBC_OPERATION_NEXT;
    bbpro_hci_msg_queue_send(&msg);

    bbpro_play_state = SBC_OPERATION_NEXT;

    return ret;
}

int bbpro_send_sbc_frame(void * data, uint8_t n_frames, uint16_t n_bytes)
{
    int ret = 0;
    unsigned int flags = 0;
    T_HCI_MSG msg;

    uos_wait_flag(sbcframe_request_flag, BTTASK_FLAG_ALL,
                  UOS_FLAG_OR_CLEAR, &flags, UOS_SUSPEND);

    ///MODLOGD("bbpro_send_sbc_frame(),data:0x%x,frames:%d,len:%d\n", data, n_frames, n_bytes);

    msg.type = HCI_MSG_TYPE_8763BF;
    msg.subtype = BBPRO_HCI_SEND_SBC_FRAME;
    msg.len = n_bytes;
    msg.flag = n_frames;
    msg.u.buf = data;
    bbpro_hci_msg_queue_send(&msg);

    return ret;
}

int bbpro_audio_control(void)
{
    T_HCI_MSG msg;
    int ret = 0;

    MODLOGD("audio control");

    msg.type = HCI_MSG_TYPE_8763BF;
    msg.subtype = BBPRO_HCI_CMD_AUDIO_CONTROL;
    bbpro_hci_msg_queue_send(&msg);

    return ret;
}

void bbpro_send_pcm_data(short * pData, unsigned short Length)
{
    int available_size;
    int write_size;
    int total_size;
    /*int ret = 0;*/
#if TX_RBUF_RWSYNC_ENABLE == 1
    OSA_STATUS osaStatus;
    uint32_t actual_flags;
#endif

    ///MODLOGD("send pcm");

    if(g_pcm_tx_rbuf == NULL) {
        MODLOGE("g_pcm_tx_rbuf NULL");
        return;
    }

#if TX_RBUF_RWSYNC_ENABLE == 1
    if(TxWaitAvailableFlag == INVALID_FLAG_ID) {
        MODLOGE("TxWaitAvailableFlag invalid");
        return;
    }
#endif

    if((total_size = bbpro_rbuf_size(g_pcm_tx_rbuf)) < Length) {
        MODLOGE("TODO: tx_rbuf total_size is too small, %d, %d", total_size, Length);
        return;
    }

    // check available free space
    if((available_size = bbpro_rbuf_available(g_pcm_tx_rbuf)) < Length) {
        MODLOGE("tx full %d,%d", available_size, Length);
#if TX_RBUF_RWSYNC_ENABLE == 1
        bTxWaitAvailable = TRUE;
        osaStatus = UOS_WaitFlag(TxWaitAvailableFlag, RBUF_HAS_AVAILABLE_SIZE | RBUF_CLEAR, OSA_FLAG_OR_CLEAR, &actual_flags, OS_SUSPEND);
        bTxWaitAvailable = FALSE;

        // check again after blocking
        available_size = bbpro_rbuf_available(g_pcm_tx_rbuf);
#else
        return;
#endif
    }

    if(bbpro_rbuf_mode(g_pcm_tx_rbuf) == RBUF_MODE_OVERWRITE)
        write_size = Length;
    else
        write_size = (available_size < Length) ? available_size : Length;

    write_size = write_size & (~1);  /* keep even */
    if(write_size) {
        /*ret =*/ bbpro_rbuf_write(g_pcm_tx_rbuf, (uint8_t *)pData, write_size);
#if TX_RBUF_RWSYNC_ENABLE == 1

#endif
    }

    ///MODLOGD("send pcm, %d, %d, %d", Length, write_size, ret);
}

void bbpro_receive_pcm_data(short * pData, unsigned short Length)
{
    int used_size;
    int read_size;
    int total_size;
    /*int ret = 0;*/
#if RX_RBUF_RWSYNC_ENABLE == 1
    OSA_STATUS osaStatus;
    uint32_t actual_flags;
#endif

    if(g_pcm_rx_rbuf == NULL) {
        MODLOGE("g_pcm_rx_rbuf NULL");
        return;
    }

#if RX_RBUF_RWSYNC_ENABLE == 1
    if(RxWaitUsedFlag == INVALID_FLAG_ID) {
        MODLOGE("RxWaitUsedFlag invalid");
        return;
    }
#endif

    if((total_size = bbpro_rbuf_size(g_pcm_rx_rbuf)) < Length) {
        MODLOGE("TODO: tx_rbuf total_size too small, %d, %d", total_size, Length);
        return;
    }

    // check available data
    if((used_size = bbpro_rbuf_used(g_pcm_rx_rbuf)) < Length) {
        MODLOGE("rx empty %d,%d", used_size, Length);
#if RX_RBUF_RWSYNC_ENABLE == 1
        // waiting
        bRxWaitUsed = TRUE;
        osaStatus = UOS_WaitFlag(RxWaitUsedFlag, RBUF_HAS_AVAILABLE_SIZE | RBUF_CLEAR, OSA_FLAG_OR_CLEAR, &actual_flags, OS_SUSPEND);
        bRxWaitUsed = FALSE;

        // check again after blocking
        used_size = bbpro_rbuf_used(g_pcm_rx_rbuf);
#else
        return;
#endif
    }

    read_size = (used_size < Length) ? used_size : Length;

    read_size = read_size & (~1);  /* keep even */
    if(read_size) {
        /*ret =*/ bbpro_rbuf_read(g_pcm_rx_rbuf, (uint8_t *)pData, read_size);

#if RX_RBUF_RWSYNC_ENABLE == 1
        if(bRxWaitAvailable) {
            UOS_SetFlag(RxWaitAvailableFlag, RBUF_HAS_AVAILABLE_SIZE, OSA_FLAG_OR);
        }
#endif
    }

    ///MODLOGD("recv pcm, %d, %d, %d", Length, read_size, ret);
}

int bbpro_send_bt_event(struct bt_task_event * event)
{
    int ret = 0;
    if(bt_user_event_handler == NULL) {

    } else {
        bt_user_event_handler(event);
    }

    return ret;
}

struct bt_task_event * bbpro_alloc_bt_event(unsigned short int event_type,
        unsigned short int event_id,
        int size)
{
    unsigned int temp;
    struct bt_task_event * event = (struct bt_task_event *)malloc(sizeof(struct bt_task_event) + size);

    if(event == NULL) {
        return NULL;
    }

    event->event_type = event_type;
    event->event_id = event_id;
    event->payload_length = size;

    if(size > 0) {
        temp = (unsigned int)&event->payload;
        temp += sizeof(void *);

        event->payload = (void *)temp;
        memset(event->payload, 0, size);
    } else {
        event->payload = NULL;
    }

    return event;
}


/**
  * @brief  Handle device state event message.
  * @param  pPacket: point to HCI event packet struct.
  * @retval None.
  */
void HandleBBProDeviceStateEvt(EVENT_DEVICE_STATE status)
{
    /* Update peer device status */
    switch(status) {
        case APP_STATE_OFF: {
            APP_PRINT_INFO0("[<--HandleBBProDeviceStateEvt] app state off!");
            RtkWristbandSys.bbpro_device_status = status;
#if 0
            {
                T_HCI_MSG msg;
                msg.type = HCI_MSG_TYPE_8763BF;
                msg.subtype = BBPRO_HCI_SEND_POWER_ON_PRESSED;
                bbpro_hci_msg_queue_send(&msg);
            }
#endif
            break;
        }
        case APP_STATE_PAIRING: {
            APP_PRINT_INFO0("[<--HandleBBProDeviceStateEvt] app state pairing!");
            RtkWristbandSys.bbpro_device_status = status;
            break;
        }
        case APP_STATE_STANDBY: {

            T_HCI_MSG msg;

            APP_PRINT_INFO0("[<--HandleBBProDeviceStateEvt] app state standby!");
            RtkWristbandSys.bbpro_device_status = status;
#if 0
            {
                T_HCI_MSG msg;
                msg.type = HCI_MSG_TYPE_8763BF;
                msg.subtype = BBPRO_HCI_SET_PLAY_MODE;
                msg.u.param = BOM_PLAY_MODE_A2DP_SOURCE;
                bbpro_hci_msg_queue_send(&msg);
            }
#endif
            MODLOGD("POWERUP_COMPLETE");
#if 0
            m_bBtPowerOn = TRUE;
            BT_SendMessage2MMI(BTSERVICE_IND_POWERUP_COMPLETE, (void *)NULL, 0);
#else
            struct bt_task_event * event = NULL;
            event = bbpro_alloc_bt_event(BTTASK_IND_TYPE_COMMON,
                                         BTTASK_IND_POWERUP_COMPLETE,
                                         0);

            bbpro_send_bt_event(event);
#endif
            msg.type = HCI_MSG_TYPE_8763BF;
            msg.subtype = BBPRO_HCI_SEND_ENTER_PAIRING_MODE;
            bbpro_hci_msg_queue_send(&msg);
            break;
        }
        case APP_STATE_CONNECTED: {
            APP_PRINT_INFO0("[<--HandleBBProDeviceStateEvt] app state connected!");
            RtkWristbandSys.bbpro_device_status = APP_STATE_CONNECTED;
            break;
        }
        case APP_STANDBY_WITH_LINK_BACK: {
            APP_PRINT_INFO0("[<--HandleBBProDeviceStateEvt] app state standby with link back!");
            RtkWristbandSys.bbpro_device_status = APP_STANDBY_WITH_LINK_BACK;
            break;
        }
        case APP_CONNECTED_WITH_LINK_BACK: {
            APP_PRINT_INFO0("[<--HandleBBProDeviceStateEvt] app state connected with link back!");
            RtkWristbandSys.bbpro_device_status = APP_CONNECTED_WITH_LINK_BACK;
            break;
        }
        default: {
            break;
        }
    }

    return;
}


/**
  * @brief  HCI event message handle callback function.
  * @param  pPacket: point to HCI packet struct.
  * @retval None.
  */
void talkband_bbpro_hci_event_cb(HCI_PackTypeDef * pPacket)
{
    uint8_t status = CMD_ACK_COMPLETE;
#if 0
    if(pPacket->opcode != HCI_EVENT_ACK) {
        APP_PRINT_INFO3("[talkband][<-hci receive raw data seq num %d ACK:false ]: %b-%02x", pPacket->seqn,
                        TRACE_BINARY(pPacket->len + 4, pPacket), pPacket->check_sum);
        /* This command is used to ack the received BBPro's event. */
    } else {
        APP_PRINT_INFO3("[talkband][<-hci receive raw data seq num %d ACK:true]: %b-%02x", pPacket->seqn,
                        TRACE_BINARY(pPacket->len + 4, pPacket), pPacket->check_sum);
    }
#endif
    /* Handle various HCI event */
    switch(pPacket->opcode) {
        case HCI_EVENT_ACK: {
            uint32_t event[4];
            if(WaitingHCIAckFlag == false) {
                MODLOGD("this is a fake ACK(%02X)!", pPacket->seqn);
            } else {
                event[0] = 0x12345678;
                if(uos_send_msg((void *)event, bbppro_hci_ack_queue_handle, UOS_SEND_EVT))
                    ///APP_PRINT_INFO0("[talkband][<-hci receive event cb] HCI event ACK!");
                    if((pPacket->payload[0] == 0x01) && (pPacket->payload[1] == 0x11)) {
                        headset_info.scan_result = INQUIRY_COMPLETE;
                    }
                ///APP_PRINT_INFO2("[ack payload]: pPacket->payload[0] is %d,pPacket->payload[1] is %d",
                ///                pPacket->payload[0],
                ///                pPacket->payload[1]);
            }
            //hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_CREATE_CONNECTION: {  // EVENT_CONNECT_STATUS
            APP_PRINT_INFO0("[talkband][<-event cb] HCI event create connection for profile!"); // for profile
            hci_cmd_send_ack(pPacket, status);
            MODLOGD("HCI_EVENT_CREATE_CONNECTION: 0x%02x(%s)", pPacket->payload[0], parseProfile(pPacket->payload[0]));

            if(pPacket->payload[0] == 0x02) {
#if 0
                BT_SendMessage2MMI(BTSERVICE_IND_HEADSET_CONNECTED, NULL, NULL);
                m_bHeadsetConnected = TRUE;
                SendMessageForBlueToothIndToMM(/*MM_BT_MSG_CONNECTED*/4, 0);
#else
                struct bt_task_event * event = NULL;
                event = bbpro_alloc_bt_event(BTTASK_IND_TYPE_COMMON,
                                             BTTASK_IND_HEADSET_CONNECTED,
                                             6);
                memcpy(event->payload, bbpro_peer_bd_addr, 6);
                event->payload_length = 6;
                bbpro_send_bt_event(event);
#endif
            }
            break;
        }
        case HCI_EVENT_DISCONNECT: {  // EVENT_DISCONNECT_STATUS
            APP_PRINT_INFO0("[talkband][<-event cb] HCI event disconnect for profile!"); // for profile
            hci_cmd_send_ack(pPacket, status);
            MODLOGD("HCI_EVENT_DISCONNECT: %d(%s)", pPacket->payload[0], parseProfile(pPacket->payload[0]));
            break;
        }
        case HCI_EVENT_DEVICE_STATE: {
            APP_PRINT_INFO1("[talkband][<-event cb] HCI event device state: %d!",
                            (EVENT_DEVICE_STATE)pPacket->payload[0]);

            hci_cmd_send_ack(pPacket, status);
            HandleBBProDeviceStateEvt((EVENT_DEVICE_STATE)pPacket->payload[0]);
            break;
        }
        case HCI_EVENT_CALL_STATUS: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_CALL_STATUS");
            hci_cmd_send_ack(pPacket, status);
            MODLOGD("HCI_EVENT_CALL_STATUS: %s(0x%02x)", parseCallStatus(pPacket->payload[1]), pPacket->payload[1]);
            break;
        }
        case HCI_EVENT_PLAYER_STATUS: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_PLAYER_STATUS");
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_LINK_STATUS: {

            MODLOGD("ACL_LINK_STATUS: %s",
                    (pPacket->payload[0] == LINK_STATUS_CONNECTED) ? "CONNECTED" :
                    (pPacket->payload[0] == LINK_STATUS_DISCONNECTED ? "DISCONNECTED" : "FAILED"));

            if(pPacket->payload[0] == 0) {
                RtkWristbandSys.bbpro_hci_link_status = BBPRO_HCI_LINK_STATE_CONNECTED;

                APP_PRINT_INFO1("[talkband][<-event cb] recv HCI_EVENT_LINK_STATUS CONNECTED bbpro_hci_link_status= %d",
                                \
                                RtkWristbandSys.bbpro_hci_link_status);
            } else if(pPacket->payload[0] == 1) {
                APP_PRINT_INFO1("[talkband][<-event cb] recv HCI_EVENT_LINK_STATUS DISCONNECT : %d",
                                pPacket->payload[0]);
                RtkWristbandSys.bbpro_hci_link_status = BBPRO_HCI_LINK_STATE_DISCONNECTED;
                headset_info.conn_result = 0;
                if(pairing_key_missing_flag == true) {
                    talkband_create_connection();//todo only for IOS
                    pairing_key_missing_flag = false;
                }
            } else {
                RtkWristbandSys.bbpro_hci_link_status = BBPRO_HCI_LINK_STATE_DISCONNECTED;
                APP_PRINT_ERROR1("[talkband][<-event cb] recv HCI_EVENT_LINK_STATUS ERROR CODE : %d",
                                 pPacket->payload[0]);
            }
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_REPORT_STATUS: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_REPORT_STATUS");
            HandleBBProDeviceStateEvt((EVENT_DEVICE_STATE)pPacket->payload[1]);
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_PAIRING_KEY_MISSING: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_PAIRING_KEY_MISSING");
            pairing_key_missing_flag = true;
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_DSP_IDLE: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_DSP_IDLE");
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_PUBLIC_ADDR: {
            APP_PRINT_INFO1("[talkband][<-event cb] hci event BT addr: %b", \
                            TRACE_BINARY(6, pPacket->payload));
            memcpy(bbpro_bd_addr, pPacket->payload, 6);
            bbpro_bd_addr_got_flag = true;
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_GET_MMI: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_GET_MMI");
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_SCO_STATUS: {
            AUDIOHAL_AIF_DEVICE_CFG_T AudioHAL_config;
            AUDIOHAL_ITF_T AudioHAL_itf = AUDIOHAL_ITF_HEADPHONE; ///AUDIOHAL_ITF_LOUDSPEAKER;

            hci_cmd_send_ack(pPacket, status);

            MODLOGD("HCI_EVENT_SCO_STATUS: %s (addr %02x%02x%02x%02x%02x%02x)",
                    pPacket->payload[6] == 1 ? "CONNECTED" : "DISCONNECTED",
                    pPacket->payload[0], pPacket->payload[1], pPacket->payload[2],
                    pPacket->payload[3], pPacket->payload[4], pPacket->payload[5]);

            if(pPacket->payload[6] == 1) {
                memset(&AudioHAL_config, 0, sizeof(AUDIOHAL_AIF_DEVICE_CFG_T));
                AudioHAL_AifOpen(AudioHAL_itf, &AudioHAL_config);

                POCVoice_BindPCMHandler(bbpro_send_pcm_data, bbpro_receive_pcm_data);

                bbpro_start_pcm_tx_timer();
            } else {
                AudioHAL_AifClose();

                POCVoice_UnBindPCMHandler(bbpro_send_pcm_data, bbpro_receive_pcm_data);

                bbpro_stop_pcm_tx_timer();
            }

            break;
        }
        case HCI_EVENT_CODEC_SETTING: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_CODEC_SETTING");
            break;
        }
        case HCI_EVENT_REPLY_PAIRED_RECORD: {
            APP_PRINT_INFO1("[talkband][<-event cb] recv HCI_EVENT_REPLY_PAIRED_RECORD num %d;",
                            pPacket->payload[0]);
            RtkWristbandSys.paired_info.paired_num = pPacket->payload[0];
            memcpy((uint8_t *)RtkWristbandSys.paired_info.newest_addr, pPacket->payload + 3, 6);
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_INITIATE_CONN_DONE: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_INITIATE_CONN_DONE");
            RtkWristbandSys.bbpro_device_status = APP_STATE_CONNECTED;
            RtkWristbandSys.bbpro_hci_link_status = BBPRO_HCI_LINK_STATE_CONNECTED;
            RtkWristbandSys.paired_info.paired_flag = true;
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_MEDIA_INFO: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_MEDIA_INFO");
            //save_media_list(pPacket->payload, pPacket->len - 2);
            if(media_info.play_pause_status == BBPRO_MUSIC_PLAY) {
                get_current_play_list(pPacket->payload + 2, pPacket->len - 2 - 2);
            } else {
                save_media_list(pPacket->payload + 2, pPacket->len - 2 - 2);
            }
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_MEDIA_INFO_SYNC_START: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI EVENT MEDIA INFO SYNC START");
            prepare_get_media_list();
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_MEDIA_INFO_SYNC_END: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI EVENT MEDIA INFO SYNC END");
            stop_get_media_list();
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_AUTHEN_FAIL: {
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_SBC_FORMAT: {
            uint8_t sampling_freq, channel_mode, block_len, subbands, alloc_method, min_bitpool, max_bitpool;

            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_SBC_FORMAT");
            hci_cmd_send_ack(pPacket, status);

            sampling_freq = pPacket->payload[0];
            channel_mode = pPacket->payload[1];
            block_len = pPacket->payload[2];
            subbands = pPacket->payload[3];
            alloc_method = pPacket->payload[4];
            min_bitpool = pPacket->payload[5];
            max_bitpool = pPacket->payload[6];
            MODLOGD("sample freq:%s", sampling_freq == 0x01 ? "16000Hz" :
                    (sampling_freq == 0x02 ? "32000Hz" :
                     (sampling_freq == 0x03 ? "44100Hz" :
                      (sampling_freq == 0x04 ? "48000Hz" :
                       "unknown"))));
            MODLOGD("channel mode: %s", channel_mode == 0x01 ? "MONO" :
                    (channel_mode == 0x02 ? "DUAL_CHANNEL" :
                     (channel_mode == 0x03 ? "STERES" :
                      (channel_mode == 0x04 ? "JOINT STEREO" :
                       "unknown"))));
            MODLOGD("block len: %d", block_len * 4);
            MODLOGD("subbands: %d", subbands * 4);
            MODLOGD("alloc_method: %s", alloc_method == 0x01 ? "SNR" :
                    (alloc_method == 0x02 ? "Loudness" :
                     "unknown"));
            MODLOGD("bitpool[%d, %d]", min_bitpool, max_bitpool);

            break;
        }

        case HCI_EVENT_REQ_AG_INDICATOR: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_REQ_AG_INDICATOR");

            hci_cmd_send_ack(pPacket, status);
            break;
        }

        case HCI_EVENT_INQURIRY_START: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_INQURIRY_START");
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_INQURIRY_COMPLETE: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_INQURIRY_COMPLETE");
//            extern bool show_inquiry;
//            show_inquiry = false;
            headset_info.scan_result = INQUIRY_COMPLETE;
            hci_cmd_send_ack(pPacket, status);

            {
#if 0
                TM_SYSTEMTIME Systime;
                TM_GetSystemTime(&Systime);

                m_btInquiryState = 3; ///BTSRV_INQUIRY_COMPLETE;

                MODLOGD("INQUIRY_COMPLETE, %0.2d:%0.2d:%0.2d\n", Systime.uHour, Systime.uMinute, Systime.uSecond);

                BT_SendMessage2MMI(BTSERVICE_IND_INQUIRY_COMPLETE, (void *)NULL, 0);
#else
                struct bt_task_event * event = NULL;
                event = bbpro_alloc_bt_event(BTTASK_IND_TYPE_COMMON,
                                             BTTASK_IND_INQUIRY_COMPLETE,
                                             0);

                bbpro_send_bt_event(event);
#endif
            }

            break;
        }
        case HCI_EVENT_INQURIRY_STOP: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_INQURIRY_STOP");
            hci_cmd_send_ack(pPacket, status);

            {
#if 0
                TM_SYSTEMTIME Systime;
                TM_GetSystemTime(&Systime);

                MODLOGD("INQURIRY_STOP, %0.2d:%0.2d:%0.2d\n", Systime.uHour, Systime.uMinute, Systime.uSecond);

                m_btInquiryState = 3; ///BTSRV_INQUIRY_COMPLETE;
                BT_SendMessage2MMI(BTSERVICE_IND_INQUIRY_COMPLETE, (void *)NULL, 0);
#else
                struct bt_task_event * event = NULL;
                event = bbpro_alloc_bt_event(BTTASK_IND_TYPE_COMMON,
                                             BTTASK_IND_INQUIRY_COMPLETE,
                                             0);

                bbpro_send_bt_event(event);
#endif
            }

            break;
        }
        case HCI_EVENT_INQURIRY_RESULT: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_INQURIRY_RESULT");
            {
#if 0
#define NAME_OFFSET     8
                uint8_t * addr;
                uint32_t len;
                uint8_t name_len, i;
                uint8_t * name;
                char buffer[MAX_BT_NAME];
                struct bt_event_inquiry * inquiry, inquiry_result;

                addr = pPacket->payload;
                len = pPacket->len - 2;
                name_len = len - NAME_OFFSET;
                name = addr + NAME_OFFSET;

                inquiry = &inquiry_result;

                memset(inquiry, 0, sizeof(struct bt_event_inquiry));
                memcpy(inquiry->addr, addr, 6);
                memcpy(inquiry->name, name, name_len);
                inquiry->length = name_len;

                MODLOGD("INQUIRY_RESULT: addr %02x%02x%02x%02x%02x%02x.\n",
                        inquiry->addr[0], inquiry->addr[1], inquiry->addr[2],
                        inquiry->addr[3], inquiry->addr[4], inquiry->addr[5]);

                for(i = 0; i < btInquiedDevice; i++) {
                    if(memcmp(inquiry->addr, ScanTable[i].addr, 6) == 0) {
                        MODLOGD("Warning: find the same device\n");
                        return;
                    }
                }

                memcpy(&ScanTable[btInquiedDevice], inquiry, sizeof(struct bt_event_inquiry));
                btInquiedDevice++;

                MODLOGD("Found %d devices\n", btInquiedDevice);

                if(inquiry->name[0] > 0x7f) {
                    int i = 0, n = 0;
                    memset(buffer, 0, MAX_BT_NAME);
                    for(i = 0; i < inquiry->length; i++) {
                        if(n >= MAX_BT_NAME - 2) // MAX-1 = '\0'
                            break;
                        n += snprintf(&buffer[n], MAX_BT_NAME - n, "%02x", inquiry->name[i]);
                    }
                    MODLOGD("name: %s\n", buffer);
                } else {
                    MODLOGD("name: %s\n", inquiry->name);
                }
                MODLOGD("name length: %d\n", inquiry->length);
                BT_SendMessage2MMI(BTSERVICE_IND_INQUIRY_RESULT, (void *)inquiry, sizeof(struct bt_event_inquiry));
#else

#define NAME_OFFSET     8
                uint8_t * addr;
                uint32_t len;
                uint8_t name_len;
                uint8_t * name;
                struct bt_event_inquiry * inquiry;
                struct bt_task_event * event = NULL;

                event = bbpro_alloc_bt_event(BTTASK_IND_TYPE_COMMON,
                                             BTTASK_IND_INQUIRY_RESULT,
                                             sizeof(struct bt_event_inquiry));

                inquiry = (struct bt_event_inquiry *)event->payload;

                addr = pPacket->payload;
                len = pPacket->len - 2;
                name_len = len - NAME_OFFSET;
                name = addr + NAME_OFFSET;

                memcpy(inquiry->addr, addr, 6);
                memcpy(inquiry->name, name, name_len);
                inquiry->length = name_len;
                inquiry->cod = COD_TYPE_HEADSET;

                MODLOGD("INQUIRY_RESULT: addr %02x%02x%02x%02x%02x%02x.\n",
                        inquiry->addr[0], inquiry->addr[1], inquiry->addr[2],
                        inquiry->addr[3], inquiry->addr[4], inquiry->addr[5]);

                bbpro_send_bt_event(event);

#endif
            }
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_MODE_STATE: {
            APP_PRINT_INFO1("[talkband][<-event cb] recv HCI EVENT MODE STATE %b ",
                            TRACE_BINARY(pPacket->len - 2, pPacket->payload));

            MODLOGD("HCI_EVENT_MODE_STATE: mode %s, state %s",
                    pPacket->payload[0] == BOM_PLAY_MODE_A2DP_SINK ? "A2DP_SINK" :
                    pPacket->payload[0] == BOM_PLAY_MODE_A2DP_SOURCE ? "A2DP_SOURCE" :
                    pPacket->payload[0] == BOM_PLAY_MODE_LOCAL_PLAYBACK ? "LOCAL_PLAYBACK" : "UNKNOWN",
                    pPacket->payload[1] == APP_PLAY_MODE_INVALID ? "INVALID" :
                    pPacket->payload[1] == APP_PLAY_MODE_INITIALIZING ? "INITIALIZING" :
                    pPacket->payload[1] == APP_PLAY_MODE_READY ? "READLY" : "UNKNOWN");

            if(pPacket->payload[0] == BOM_PLAY_MODE_A2DP_SINK) {
                T_HCI_MSG msg;
                msg.type = HCI_MSG_TYPE_8763BF;
                msg.subtype = BBPRO_HCI_SEND_ENTER_PAIRING_MODE;
                bbpro_hci_msg_queue_send(&msg);
            } else if(pPacket->payload[0] == BOM_PLAY_MODE_A2DP_SOURCE) {
                if(pPacket->payload[1] == 0x02) {
                    headset_info.conn_result = 1;
                    APP_PRINT_INFO0("RECEIVE CONNRESULT");
                }
            }
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_PLAY_STATUS: {
            if(pPacket->payload[1] == 0x03) {
                media_info.cur_select++;
                if(media_info.cur_select >= media_info.had_scaned_list_num) {
                    media_info.cur_select = 0;
                }
                APP_PRINT_INFO2("media_info.cur_select IS %d,media_info.had_scaned_list_num is %d", \
                                media_info.cur_select, media_info.had_scaned_list_num);
            } else if(pPacket->payload[1] == 0x04) {
                if(media_info.cur_select == 0) {
                    media_info.cur_select = media_info.had_scaned_list_num - 1;
                } else {
                    media_info.cur_select--;
                }
            } else if(pPacket->payload[1] == 0x01) {
                media_info.play_pause_status = 0x01;
            } else if(pPacket->payload[1] == 0x02) {
                media_info.play_pause_status = 0x00;
            } else if(pPacket->payload[1] == 0x0) {
                media_info.play_pause_status = 0x00;
            }
            APP_PRINT_INFO1("HCI_EVENT_PLAY_STATUS IS %d", pPacket->payload[1]);
            break;
        }
        case HCI_EVENT_PLAYLIST_CHANGED: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_PLAYLIST_CHANGED");
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_REPORT_ERR_CODE: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_REPORT_ERR_CODE");
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_LE_CONNECTED: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_LE_CONNECTED");
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_LE_DISCONNECTED: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_LE_DISCONNECTED");
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_LE_PAIR_STATUS: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_LE_PAIR_STATUS");
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_LE_DATA_TRANSFER: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_LE_DATA_TRANSFER");
            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_REQ_SBC_FRAME: {
            ///APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_REQ_SBC_FRAME, seqn %02X, %d", pPacket->seqn, pPacket->payload[0]);

            hci_cmd_send_ack(pPacket, status);

            uos_set_flag(sbcframe_request_flag, MEDIA_PROCESS_FLAG_CONTINUE, UOS_FLAG_OR);

            break;
        }
        case HCI_EVENT_WATERWORLD_PLAY_STATUS: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_WATERWORLD_PLAY_STATUS");

            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_I2S_REQUIREMENT: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_I2S_REQUIREMENT");

            hci_cmd_send_ack(pPacket, status);

            MODLOGD("i2s requirment: %d", pPacket->payload[0]);
#if 0
            if(pPacket->payload[0])
                hci_cmd_send_i2s_status(1);
#endif
            break;
        }
        case HCI_EVENT_HF_INDICATOR: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_HF_INDICATOR %d %d", pPacket->payload[0], pPacket->payload[1]);

            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_HF_VOLUME_SYNC: {
            APP_PRINT_INFO0("[talkband][<-event cb] recv HCI_EVENT_HF_VOLUME_SYNC %d %d", pPacket->payload[0], pPacket->payload[1]);

            hci_cmd_send_ack(pPacket, status);
            break;
        }
        case HCI_EVENT_AUDIO_CONTROL: {
            MODLOGD("HCI_EVENT_AUDIO_CONTROL");

            break;
        }
        case HCI_EVENT_AUDIO_DATA: {
            uint16_t Length = pPacket->len - HCI_OPCODE_WIDTH - HCI_AUDIO_DATA_SEQN_WIDTH;
            int available_size;
            int write_size;
            int total_size;
            /*int ret = 0;*/
#if RX_RBUF_RWSYNC_ENABLE == 1
            OSA_STATUS osaStatus;
            uint32_t actual_flags;
#endif

            ///MODLOGD("AUDIO_DATA, seqn: 0x%04x", (pPacket->payload[1]<<8 | pPacket->payload[0]));

            extern void debug_dump_uart(void * buf, int len);
            debug_dump_uart(&pPacket->payload[HCI_AUDIO_DATA_INDEX], Length);

            if(Length != HCI_AUDIO_DATA_WIDTH)
                return;

            if(g_pcm_rx_rbuf == NULL) {
                MODLOGE("g_pcm_rx_rbuf NULL");
                return;
            }

            if((total_size = bbpro_rbuf_size(g_pcm_rx_rbuf)) < Length) {
                MODLOGE("TODO: rx_rbuf total_size is too small, %d, %d", total_size, Length);
            }

            // check available free space
            if((available_size = bbpro_rbuf_available(g_pcm_rx_rbuf)) < Length) {
                MODLOGE("rx full %d,%d", available_size, Length);
#if RX_RBUF_RWSYNC_ENABLE == 1
                // waiting
                bRxWaitAvailable = TRUE;
                osaStatus = UOS_WaitFlag(RxWaitAvailableFlag, RBUF_HAS_AVAILABLE_SIZE | RBUF_CLEAR, OSA_FLAG_OR_CLEAR, &actual_flags, OS_SUSPEND);
                bRxWaitAvailable = FALSE;

                // check again after blocking
                available_size = bbpro_rbuf_available(g_pcm_rx_rbuf);
#else
                break;
#endif
            }

            write_size = (available_size < Length) ? available_size : Length;

            write_size = write_size & (~1);  /* keep even */
            if(write_size) {
                /*ret =*/ bbpro_rbuf_write(g_pcm_rx_rbuf, &pPacket->payload[HCI_AUDIO_DATA_INDEX], write_size);
#if RX_RBUF_RWSYNC_ENABLE == 1
                if(bRxWaitUsed) {
                    UOS_SetFlag(RxWaitUsedFlag, RBUF_HAS_AVAILABLE_SIZE, OSA_FLAG_OR);
                }
#endif
            }
            ///MODLOGD("event pcm, %d, %d, %d", Length, write_size, ret);
            break;
        }
        default: {
            MODLOGD("unhandle opcode: 0x%x!", pPacket->opcode);
            hci_cmd_send_ack(pPacket, status);
            break;
        }
    }
}

void talkband_create_connection(void)
{
    T_HCI_MSG msg;
    extern uint8_t bbpro_peer_bd_addr[];

    msg.type = HCI_MSG_TYPE_8763BF;
    msg.subtype = BBPRO_HCI_SEND_POWER_ON_PRESSED;
    bbpro_hci_msg_queue_send(&msg);
    msg.subtype = BBPRO_HCI_SEND_POWER_ON_RELEASED;
    bbpro_hci_msg_queue_send(&msg);

    msg.subtype = BBPRO_HCI_CREATE_CONNECTION;
    msg.len = 6;
    msg.u.buf = bbpro_peer_bd_addr;
    bbpro_hci_msg_queue_send(&msg);
}

#endif/*USE_LV_BLUETOOTH*/

/******************* (C) COPYRIGHT 2018 Realtek Semiconductor Corporation *****END OF FILE****/

